今天的守則接續昨天的內容,昨天提到的是盡量pass by reference,今天則是反過來提醒不要走火入魔該return object的時候也return 到reference啦~ 一起來看看吧!
今天的守則是:
Don't try to return a reference when you must return an object
如前言所提到的,雖然傳入function的時候多半傳reference比較好,而不要pass by value,但return的時候就不是這樣了。因為你很有可能開始傳 不存在的物件的reference!
return的時候可以不要return value嗎?可以也return reference嗎?此時我們就要回頭釐清 reference究竟是什麼─ reference其實就是一個 名字,而它一定要refer到一個 存在的object。一個簡單的判斷方法:看到reference的宣告,可以想想看它的另外一個名字是什麼?因為它一定是某一個現存的 物件。
那如果今天,有一個function的行為,是要return一個物件,但它目前還不存在,那要怎麼辦?首先就是要create出這個object了。
function可以創建新物件有兩種─on stack或是on heap。stack就是創建 local variable。那我們可以return local object的reference嗎?答案顯然不行,因為local obkect在function結束的時候就會被destroy掉了。這樣return的就是已經 不存在的物件的reference,結果就是undefined behavior。return local object的pointer也是如此。
那考慮一下 heap呢?Heap-based object是由new
來生成的,那我們可以return一個new出來的object的reference嗎?這則會有另一個問題─ 誰來管理return出來的object的資源呢?就是delete
的部分。有些情況下,這些資源有可能不會被管理到。例如這種情形:
const Rational& operator*(const Rational& lhs, const Rational& rhs)
{
Rational *result = new Rational(lhr.n* rhs.n, lhs.d * rhs.d);
return *result;
}
Rational w, x, y, z;
w = x * y * z;
每一個operator*
都會產生一個new
的object,那應該要有兩個delete
來做對應處理,但很明顯現在這樣一定會有resource leak!
以上兩種方法都行不通,而且沒有省掉constructor─畢竟你create物件的時候一樣也有用到constructor,此時可能又有一個大膽的想法─ return static object 的reference怎麼樣?每次執行的時候重複使用同一個static object,那不就可以省掉每次重新創建一個新物件的constructor了嗎?
細想下去就會發現不行了─ 這會有thread問題!且如果同時有人去call這到它,它們會return到同樣的東西!
例如以下:
const Rational& operator*(const Rational& lhs, const Rationl& rhs)
{
static Rational result;
result = ...
return result;
}
Rational a, b, c, d;
if((a*b) == (c*d)) // always the same regardless of the values of a b c d!!
{
...
}
說了這麼多,其實就是要說明一件事─ 想從一個function裡面return reference基本上是不太合理的事。該return new object的時候就認命return 一個新物件吧!而且我們煩惱的construction, destruction耗費運算時間的問題,其實很多都會被compiler優化掉。
貼心重點提醒:
- Never return a pointer or reference to a local stack object, a reference to a heap-allocated object, or a pointer or reference to a local static object if there is a change that more than one such object will be needed.
附註: return reference to a local static在single-threaded enviornments有合理用法